#ifndef __UNIQUE_ONLY__

#define __UNIQUE_ONLY__ 
#endif

//0 默认  1 只打印  2 打印并存储在一个文件  默认 打印并分类存文件 3 不打印，只写同一个文件 4 不打印，分类写

#include<iostream>
#include<stdarg.h>
#include<stdio.h>
#include<string>
#include<time.h>
#include<vector>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

enum grade
{
  Info,      //常规 0
  Warning,   //警告 1
  Error,     //错误 2
  Fatal,     //致命 3
  Debug      //调试 4
};

//日志 等级 + 时间 + 行号 + 内容
namespace xxhhdzl
{
  class log
  {
  public:
    log(size_t flag = 0)
      :_flag(flag)
    {}


    void operator()(size_t grade, int line, const char* s, ...)
    {
      std::string ans; 
      //等级
      std::string s1 = getGrade(grade);
      
      //时间
      time_t t = time(nullptr);
      struct tm* m = localtime(&t);

      char s2[1024] = {'\0'};
      snprintf(s2, 1024, "[%s][time: %d - %d - %d %d:%d:%d][Line numbre: %d]", s1.c_str(), m->tm_year + 1900, m->tm_mon + 1, m->tm_mday, m->tm_hour, m->tm_min, m->tm_sec, line);

      //内容
      va_list s3;
      va_start(s3, s);
      char s4[1024] = {'\0'};
      vsnprintf(s4, 1024, s, s3);

      //拼接
      ans += s2;
      ans += "[content: "; 
      ans += s4; 
      ans += "]";
      ans += "\n";
      _log.push_back(ans);
    }

    //输出日志文件
    
    ~log()
    {
      switch(_flag)
      {
        case 0:
          for (auto s : _log)
          {
            std::cout << s << std::endl;
          }
          outputClassfile(); 
          break;
        case 1:
          for (auto s : _log)
          {
            std::cout << s << std::endl;
          }
          break;
        case 2:
          for (auto s : _log)
          {
            std::cout << s << std::endl;
          }
          outputOnefile();
          break;
        case 3:
          outputOnefile();
          break;
        case 4:
          outputClassfile();
          break;
        default:
          operator()(Error, 98, "flag set error");
          for (auto s : _log)
          {
            std::cout << s << std::endl;
          }
        break;
      }
    }

  private:
    bool outputOnefile()
    {
      int fd = open("./log.log",O_CREAT | O_WRONLY | O_APPEND, 0666);
      if (fd == -1)
      {
        operator()(Error, 115, "uotputOnefile create file lose");
        return false;
      }

      for (auto s : _log)
      {
        int c = write(fd, s.c_str(), s.size());
        if (c == -1)
        {
          operator()(Error, 124, "write file lose");
          return false;
        }
      }
      close(fd);
      return true;
    }

    bool outputClassfile()
    {
      mkdir("./log", 0777);

      std::vector<int> fd(6);
      for (int i = 0; i <= 5; i++)
      {
        std::string s = "./log/"; 
        s += "log_" + getGrade(i);
        s += ".log";
        int c = open(s.c_str(),O_CREAT | O_WRONLY | O_APPEND, 0666);
        if (c == -1)
        {
          operator()(Error, 145, "uotputClassfile create file lose");
          return false;
        }
        fd[i] = c;
      }

      for (auto s : _log)
      {
        int end = s.find("]");
        std::string t = s.substr(1, end - 1);

        int c = write(fd[Grade(t)], s.c_str(), s.size());
        if (c == -1)
        {
          operator()(Error, 159, "write file lose");
          return false;
        }
      }

      for (auto f : fd)
      {
        close(f);
      }
      return true;
    }

    int Grade(std::string& g)
    {
      if (g == "Info")
      {
        return 0;
      }
      else if (g == "Warning")
      {
        return 1;
      }
      else if (g == "Error")
      {
        return 2;
      }
      else if (g == "Fatal")
      {
        return 3;
      }
      else if (g == "Debug")
      {
        return 4;
      }

      return 5;
    }


    static std::string getGrade(size_t g)
    {
      switch (g)
      {
        case Info:
          return "Info";
          break;  
        case Warning:
          return "Warning";
          break;
        case Error:
          return "Error";
          break;
        case Fatal:
          return "Fatal";
          break;
          case Debug:
          return "Debug";
          break;
        default:
          return "None";
          break;
      }
    }
    
    //0 默认  1 只打印  2 打印并存储在一个文件  默认 打印并分类存文件 3 不打印，只写同一个文件 4 不打印，分类写
    size_t _flag;
    //暂时存储日志
    std::vector<std::string> _log;
  };
}
